package com.mzj.saas.mservice.property.service;

import cn.hutool.core.util.StrUtil;
import com.mzj.saas.commons.ApiData;
import com.mzj.saas.commons.ConvertUtils;
import com.mzj.saas.commons.ResultBean;
import com.mzj.saas.commons.util.DataUtils;
import com.mzj.saas.commons.util.StringUtils;
import com.mzj.saas.commons.vo.redis.TokenRedisVo;
import com.mzj.saas.mservice.community.entity.Community;
import com.mzj.saas.mservice.community.repository.CommunityRepository;
import com.mzj.saas.mservice.community.service.AppCommunityService;
import com.mzj.saas.mservice.property.common.CostTypeEnum;
import com.mzj.saas.mservice.property.entity.EstateRepairsCost;
import com.mzj.saas.mservice.property.repository.EstateRepairsCostRepository;
import com.mzj.saas.mservice.property.vo.EstateRepairsCostV2VO;
import com.mzj.saas.mservice.property.vo.EstateRepairsCostVO;
import com.mzj.saas.mservice.property.vo.RepairsCostListVO;
import com.mzj.saas.mservice.sys.entity.AppUser;
import com.mzj.saas.mservice.sys.repository.AppUserRepository;
import com.mzj.saas.mservice.sys.utils.SqlUtils;
import com.mzj.saas.redis.RedisService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author hikari
 * @since 2021-05-20
 */
@Service
public class EstateRepairsCostService {
    private static final Logger log = LoggerFactory.getLogger(EstateRepairsCostService.class);

    private static final String ORDER = " ORDER BY c.operator_time DESC";
    private static final String SQL_PAGE = " LIMIT ? OFFSET ?";

    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    @Autowired
    private RedisService redisService;
    @Autowired
    private AppUserRepository appUserRepository;
    @Autowired
    private EstateRepairsCostRepository estateRepairsCostRepository;
    @Autowired
    private CommunityRepository communityRepository;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private AppCommunityService appCommunityService;

    public EstateRepairsCost findById(Long id) {
        return estateRepairsCostRepository.findById(id).orElse(null);
    }

    /**
     * 小区收费数据封装
     * @param cost
     * @return
     */
    public EstateRepairsCostVO convertToVO(EstateRepairsCost cost) {
        EstateRepairsCostVO estateRepairsCostVO = new EstateRepairsCostVO();
        estateRepairsCostVO.setId(cost.getId());
        estateRepairsCostVO.setCommunityId(cost.getCommunityId());
        communityRepository.findById(cost.getCommunityId()).ifPresent(community -> estateRepairsCostVO.setCommunityName(community.getName()));
        estateRepairsCostVO.setType(cost.getType());
        estateRepairsCostVO.setTypeName(CostTypeEnum.getTypeName(cost.getType()));
        estateRepairsCostVO.setRepairItem(cost.getRepairItem());
        BigDecimal materialsCost = DataUtils.IntegerToBigdecimal(cost.getMaterialsCost());
        estateRepairsCostVO.setMaterialsCost(materialsCost);
        estateRepairsCostVO.setModel(cost.getModel());
        BigDecimal serviceCost = DataUtils.IntegerToBigdecimal(cost.getServiceCost());
        estateRepairsCostVO.setServiceCost(serviceCost);
        estateRepairsCostVO.setOperatorId(cost.getOperatorId());
        /*AppUser user = appUserRepository.findByIdOrEnterpriseUserId(cost.getOperatorId(), cost.getOperatorId());
        if (user != null) {
            estateRepairsCostVO.setOperatorName(user.getName());
        }*/
        estateRepairsCostVO.setOperatorTime(cost.getOperatorTime());
        estateRepairsCostVO.setStatus(cost.getStatus());

        return estateRepairsCostVO;
    }

    /**
     * 查小区收费项目
     * @param accessToken
     * @param communityId 小区id
     * 当前小区收费项目
     */
    public ResultBean<List<EstateRepairsCostV2VO>> listByCommunityId(String accessToken, String communityId) {
        try {
            TokenRedisVo token = redisService.findTokenVo(accessToken);
            if (token == null) return ResultBean.failedResultOfToken();

            List<EstateRepairsCost> costs = estateRepairsCostRepository.findByCommunityId(communityId);
            List<EstateRepairsCostVO> voList = new ArrayList<>();
            for (EstateRepairsCost cost : costs) {
                EstateRepairsCostVO vo = convertToVO(cost);
                voList.add(vo);
            }

            //根据类型分组
            Map<String, List<EstateRepairsCostVO>> collect = voList.stream().collect(Collectors.groupingBy(d -> d.getCommunityId() + ":" + d.getType()));
            List<EstateRepairsCostV2VO> v2VOList = new ArrayList<>();
            for (String key : collect.keySet()) {
                List<EstateRepairsCostVO> repairsCostVOS = collect.get(key);
                EstateRepairsCostV2VO v2VO = new EstateRepairsCostV2VO();
                v2VO.setCommunityId(repairsCostVOS.get(0).getCommunityId());
                v2VO.setCommunityName(repairsCostVOS.get(0).getCommunityName());
                v2VO.setType(repairsCostVOS.get(0).getType());
                v2VO.setTypeName(repairsCostVOS.get(0).getTypeName());
                v2VO.setItems(repairsCostVOS);
                v2VOList.add(v2VO);
            }

            return ResultBean.successfulResult(v2VOList);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<ApiData<EstateRepairsCostV2VO>> list(String accessToken, Integer type, String repairItem,
                                                           String model, String communityId, String creator,
                                                           Integer pageNumber, Integer pageSize) {
        try {
            TokenRedisVo token = redisService.findTokenVo(accessToken);
            if (token == null) return ResultBean.failedResultOfToken();

            String querySql = "SELECT * FROM saas_estate_repairs_cost WHERE 1 = 1";
            String countSql = "SELECT COUNT(*) FROM saas_estate_repairs_cost WHERE 1 = 1";
            Map<String, Object> params = new HashMap<>();
            params.put("limit", pageSize);
            params.put("offset", pageSize * pageNumber);

            if (type != null) {
                params.put("type", type);
                querySql += " AND type = :type ";
                countSql += " AND type = :type ";
            }

            if (!StringUtils.isEmpty(repairItem)) {
                params.put("repairItem", "%" + repairItem + "%");
                querySql += " AND repair_item LIKE :repairItem ";
                countSql += " AND repair_item LIKE :repairItem ";
            }

            if (!StringUtils.isEmpty(model)) {
                params.put("model", "%" + model + "%");
                querySql += " AND model LIKE :model ";
                countSql += " AND model LIKE :model ";
            }

            if (!StringUtils.isEmpty(communityId)) {
                params.put("communityId", communityId);
                querySql += " AND community_id = :communityId ";
                countSql += " AND community_id = :communityId ";
            }

            if (!StringUtils.isEmpty(creator)) {
                List<AppUser> users = appUserRepository.findByNameLike("%" + creator + "%");
                List<String> userIdList = users.stream().map(AppUser::getId).collect(Collectors.toList());
                params.put("operatorIdList", userIdList);
                querySql += " AND operator_id IN (:operatorIdList) ";
                countSql += " AND operator_id IN (:operatorIdList) ";
            }

            querySql += " LIMIT :limit OFFSET :offset ";

            List<EstateRepairsCost> costList = namedParameterJdbcTemplate.query(querySql, params, new BeanPropertyRowMapper<>(EstateRepairsCost.class));
            Long count = namedParameterJdbcTemplate.queryForObject(countSql, params, Long.class);

            List<EstateRepairsCostVO> voList = new ArrayList<>();
            for (EstateRepairsCost cost : costList) {
                EstateRepairsCostVO costVO = convertToVO(cost);
                voList.add(costVO);
            }

            Map<String, List<EstateRepairsCostVO>> collect = voList.stream().collect(Collectors.groupingBy(d -> d.getCommunityId() + ":" + d.getType()));

            List<EstateRepairsCostV2VO> v2VOList = new ArrayList<>();
            for (String key : collect.keySet()) {
                List<EstateRepairsCostVO> repairsCostVOS = collect.get(key);
                EstateRepairsCostV2VO v2VO = new EstateRepairsCostV2VO();
                v2VO.setCommunityId(repairsCostVOS.get(0).getCommunityId());
                v2VO.setCommunityName(repairsCostVOS.get(0).getCommunityName());
                v2VO.setType(repairsCostVOS.get(0).getType());
                v2VO.setTypeName(repairsCostVOS.get(0).getTypeName());
                v2VO.setItems(repairsCostVOS);
                v2VOList.add(v2VO);
            }

            ApiData<EstateRepairsCostV2VO> apiData = new ApiData<>();
            apiData.setTotal(count);
            apiData.setData(v2VOList);

            return ResultBean.successfulResult(apiData);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    /**
     * 新增收费项目
     * @param accessToken
     * @param estateRepairsCostVO
     * @return
     */
    public ResultBean<EstateRepairsCostVO> save(String accessToken, EstateRepairsCostVO estateRepairsCostVO) {
        try {
            TokenRedisVo token = redisService.findTokenVo(accessToken);
            if (token == null) return ResultBean.failedResultOfToken();
            String userId = token.getId();
            String userName = token.getName();

            String model = estateRepairsCostVO.getModel();
            if (StrUtil.isBlank(model) || StrUtil.length(model) > 20){
                return ResultBean.failedResultOfParamWithMsg("型号规格不得为空/长度不得超过20字");
            }
            String repairItem = estateRepairsCostVO.getRepairItem();
            if (StrUtil.isBlank(repairItem) || StrUtil.length(repairItem) > 20){
                return ResultBean.failedResultOfParamWithMsg("维修项目不得为空/长度不得超过20字");
            }
            /*if (estateRepairsCostVO.getMaterialsCost() < 0) {
                return ResultBean.failedResultOfParamWithMsg("材料费不能小于0");
            }

            if (estateRepairsCostVO.getServiceCost() < 0) {
                return ResultBean.failedResultOfParamWithMsg("劳务费不能小于0");
            }*/

            EstateRepairsCost cost = new EstateRepairsCost();
            cost.setId(estateRepairsCostVO.getId());
            cost.setCommunityId(estateRepairsCostVO.getCommunityId());
            cost.setType(estateRepairsCostVO.getType());
            cost.setRepairItem(estateRepairsCostVO.getRepairItem());
            cost.setMaterialsCost(ConvertUtils.yuan2fen(estateRepairsCostVO.getMaterialsCost()));
            cost.setModel(estateRepairsCostVO.getModel());
            cost.setServiceCost(ConvertUtils.yuan2fen(estateRepairsCostVO.getServiceCost()));
            cost.setOperatorId(userId);
            cost.setOperatorName(userName);
            cost.setOperatorTime(new Date());
            cost.setStatus(1);

            EstateRepairsCost save = estateRepairsCostRepository.save(cost);
            EstateRepairsCostVO costVO = convertToVO(save);

            return ResultBean.successfulResult(costVO);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    /**
     * 删除收费项目
     * @param accessToken
     * @param id
     * 根据id删
     */
    public ResultBean<Object> delete(String accessToken, Long id) {
        try {
            TokenRedisVo token = redisService.findTokenVo(accessToken);
            if (token == null) return ResultBean.failedResultOfToken();

            estateRepairsCostRepository.deleteById(id);

            return ResultBean.successfulResult(null);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    /**
     * 收费项目列表-企业端
     * @param accessToken
     * @param type 项目类型
     * @param repairItem 维修项目
     * @param model 规格
     * @param communityId 小区id
     * @param creator 创建人
     * @param pageNumber
     * @param pageSize
     * @return
     */
    public ResultBean<ApiData<RepairsCostListVO>> repairsCostList(String accessToken, Integer type, String repairItem,
                                                                  String model, String communityId, String creator,
                                                                  Integer pageNumber, Integer pageSize) {
        ResultBean<ApiData<RepairsCostListVO>> resultBean = new ResultBean<>();
        resultBean.setCode("10000");
        resultBean.setMsg("10000");
        ApiData<RepairsCostListVO> apiData = new ApiData<>();
        resultBean.setResultData(apiData);
        try {
            //校验登录信息
            TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
            if (tokenRedisVo == null) {
                return ResultBean.failedResultOfToken();
            }

            StringBuilder where = new StringBuilder();
            List<Object> args = new ArrayList<>();
            where.append(" where 1 = 1");

            //权限过滤
            List<Map<String, Object>> communityList = appCommunityService.findCommunity(accessToken).getResultData();
            if (communityList != null && !communityList.isEmpty()) {
                where.append(" and c.community_id in " + SqlUtils.foreachIn(communityList.size()));
                List<String> communityIds = communityList.stream().map(map -> {
                    String comId = map.get("communityId").toString();
                    return comId;
                }).collect(Collectors.toList());
                args.addAll(communityIds);
            } else {
                where.append(" and c.community_id in (null)");
            }

            //条件查询
            if (type != null) {
                where.append(" AND c.`type` = ?");
                args.add(type);
            }
            if (StringUtils.isNotBlank(repairItem)) {
                where.append(" AND c.`repair_item` = ?");
                args.add(repairItem);
            }
            if (StringUtils.isNotBlank(model)) {
                where.append(" AND c.`model` = ?");
                args.add(model);
            }
            if (StringUtils.isNotBlank(communityId)) {
                where.append(" AND c.`community_id` = ?");
                args.add(communityId);
            }
            if (StringUtils.isNotBlank(creator)) {
                where.append(" AND c.`operator_name` = ?");
                args.add(creator);
            }

            // 总记录数
            Long total = jdbcTemplate.queryForObject("SELECT count(1) FROM `saas_estate_repairs_cost` c" + where, args.toArray(), Long.class);
            if (total == 0) {
                return resultBean;
            }

            args.add(pageSize);
            args.add(pageNumber * pageSize);
            List<EstateRepairsCost> list = jdbcTemplate.query("SELECT * FROM `saas_estate_repairs_cost` c" + where + ORDER + SQL_PAGE,
                    new BeanPropertyRowMapper<>(EstateRepairsCost.class), args.toArray());

            //封装数据
            List<RepairsCostListVO> data = new ArrayList<>();
            for (EstateRepairsCost cost : list) {
                RepairsCostListVO vo = new RepairsCostListVO();
                vo.setId(cost.getId());
                vo.setCommunityId(cost.getCommunityId());
                vo.setType(cost.getType());
                vo.setRepairItem(cost.getRepairItem());
                vo.setMaterialsCost(DataUtils.IntegerToBigdecimal(cost.getMaterialsCost()));
                vo.setModel(cost.getModel());
                vo.setServiceCost(DataUtils.IntegerToBigdecimal(cost.getServiceCost()));
                vo.setOperatorId(cost.getOperatorId());
                vo.setOperatorName(cost.getOperatorName());
                data.add(vo);
            }

            // 查询小区名称
            List<String> communityIds = data.stream().filter(vo -> vo.getCommunityId() != null).map(RepairsCostListVO::getCommunityId).distinct().collect(Collectors.toList());
            if (!communityIds.isEmpty()) {
                Map<String, String> map = communityRepository.findByIdIn(communityIds).stream().collect(Collectors.toMap(Community::getId, Community::getName));
                if (!map.isEmpty()) {
                    data.forEach(vo -> vo.setCommunityName(map.get(vo.getCommunityId())));
                }
            }

            apiData.setData(data);
            apiData.setTotal(total);

            resultBean.setResultData(apiData);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            resultBean.setCode("10001");
            resultBean.setMsg("10001");
        }
        resultBean.setResultData(apiData);
        return resultBean;
    }


}
